#   ++++++++++++++++++ CMAKE FUNCTIONS ++++++++++++++++++++++#

# \brief 函数名称 : export_symbol【导出逻辑】
# @target      : 库目标
# @location    : 生成位置
function(export_symbol target location)
    if (NOT TARGET ${target})
        message(FATAL_ERROR "目标 ${target} 不存在，无法导出符号")
    endif ()
    if (NOT location)
        message(FATAL_ERROR "缺少导出文件路径参数")
    endif ()
    string(TOUPPER ${target} TARGET_NAME)

    set(dst "${CMAKE_CURRENT_SOURCE_DIR}/${location}/export.h")
    if (NOT EXISTS ${dst})
        configure_file("../cmake/global_template.h.in"
                "${CMAKE_CURRENT_SOURCE_DIR}/${location}/export.h"
                @ONLY)
    endif ()
    target_compile_definitions(${target} PRIVATE "${TARGET_NAME}_LIBRARY")
endfunction()


# \brief 函数名称 : add_unit_test【添加单元测试】
# @target_name      : 测试目标名称
# @dir_name         : 目录名称【递归查找】
# @moudle           : 模块
function(add_unit_test target_name dir_name module)
    find_package(Qt5 COMPONENTS Widgets Core Gui Test REQUIRED)
    if (NOT target_name)
        message(FATAL_ERROR "缺少测试目标名称参数")
    endif ()
    if (NOT dir_name)
        message(FATAL_ERROR "缺少文件参数")
    endif ()
    if (NOT TARGET ${module})
        message(FATAL_ERROR "传入module参数非可用目标")
    endif ()
    file(GLOB_RECURSE "${target_name}_src" CONFIGURE_DEPENDS "${dir_name}/*.cpp" "${dir_name}/*.h")
    add_executable(${target_name} "${${target_name}_src}")
    target_link_libraries(${target_name} PRIVATE
            Qt5::Core
            Qt5::Gui
            Qt5::Widgets
            Qt5::Test
            ${module}
    )
    add_test(NAME ${target_name} COMMAND ${target_name}
            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
    )
endfunction()


# 获取某个 target 的所有 imported 动态库依赖（递归）
# 用法: get_imported_shared_libs(<target> <out_var> [<visited>])
function(get_imported_shared_libs target out_var)
    if (NOT TARGET ${target})
        set(${out_var} "" PARENT_SCOPE)
        return()
    endif ()

    # 避免循环
    set(visited ${ARGN})
    list(FIND visited ${target} idx)
    if (NOT idx EQUAL -1)
        set(${out_var} "" PARENT_SCOPE)
        return()
    endif ()
    list(APPEND visited ${target})

    # 当前构建配置
    if (CMAKE_BUILD_TYPE)
        string(TOUPPER ${CMAKE_BUILD_TYPE} CONFIG_UPPER)
    else ()
        set(CONFIG_UPPER $<CONFIG>)
    endif ()

    set(result "")

    # 收集直接依赖
    set(all_libs "")
    get_target_property(direct_libs ${target} LINK_LIBRARIES)
    if (direct_libs)
        list(APPEND all_libs ${direct_libs})
    endif ()
    get_target_property(interface_libs ${target} INTERFACE_LINK_LIBRARIES)
    if (interface_libs)
        list(APPEND all_libs ${interface_libs})
    endif ()

    foreach (lib IN LISTS all_libs)
        if (TARGET ${lib})
            get_target_property(dep_type ${lib} TYPE)

            if (NOT dep_type STREQUAL "STATIC_LIBRARY")
                # 尝试获取动态库文件位置
                set(loc "")
                get_target_property(loc ${lib} IMPORTED_LOCATION_${CONFIG_UPPER})
                if (NOT loc)
                    get_target_property(loc ${lib} IMPORTED_LOCATION)
                endif ()

                if (loc)
                    list(APPEND result ${loc})
                endif ()
            endif ()

            # 递归
            get_imported_shared_libs(${lib} child_libs ${visited})
            list(APPEND result ${child_libs})
        endif ()
    endforeach ()

    # 去重
    list(REMOVE_DUPLICATES result)

    # 返回给调用者
    set(${out_var} "${result}" PARENT_SCOPE)
endfunction()


# \brief 函数名称 : copy_target_dependencies【拷贝目标依赖】
# @target      : 目标
# @visited     : 避免循环依赖
function(copy_imported_dependencies target dest_dir)
    if (COPY_3RD_LIB)
        get_imported_shared_libs(${target} deps)

        if (${target} STREQUAL "cxi_common")
            # 保存到 Cache
            set(DEPS_cxi_common "${deps}" CACHE INTERNAL "Imported deps for cxi_common")
            message(STATUS "已保存cxi_common依赖到 Cache: ${deps}")
        endif ()

        foreach (lib IN LISTS deps)
            file(COPY ${lib} DESTINATION ${dest_dir})
            message(STATUS "已拷贝依赖: ${lib} -> ${dest_dir}")
        endforeach ()
    endif (COPY_3RD_LIB)
endfunction()

# \brief 函数名称 : install_imported_dependencies【安装导入的依赖】
# @target      : 目标
# @dest_dir     : 安装目录
function(install_imported_dependencies target dest_dir)
    install(FILES ${DEPS_cxi_common} DESTINATION ${DESIGNER_DEST_DIR}/bin)
endfunction()


# \brief 函数名称 : install_designer_dependencies【安装设计师依赖】
function(install_designer_dependencies)
    if (NOT CMAKE_BUILD_TYPE STREQUAL "Release")
        return()
    endif ()

    # 安装 cxi_controls, cxi_common 本身
    install(TARGETS cxi_controls cxi_common
            RUNTIME DESTINATION ${DESIGNER_DEST_DIR}/bin
            LIBRARY DESTINATION ${DESIGNER_DEST_DIR}/bin
    )

    # 安装 cxi_common 的依赖库
    install_imported_dependencies(cxi_common ${DESIGNER_DEST_DIR}/bin)

    # 安装 cxi_designer
    install(TARGETS cxi_designer
            RUNTIME DESTINATION ${DESIGNER_DEST_DIR}/plugins/designer
            LIBRARY DESTINATION ${DESIGNER_DEST_DIR}/plugins/designer
    )
endfunction()


# \brief 函数名称 : install_qt_libs【安装Qt库】
# @QT_LIBS      : Qt库列表
# @dest_dir     : 安装目录
function(install_qt_libs dest_dir)
    set(options)
    set(oneValueArgs)
    set(multiValueArgs QT_LIBS)
    cmake_parse_arguments(INSTALL_QT_LIBS
            "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
        set(DEBUG_SUFFIX)
        if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
            set(DEBUG_SUFFIX "d")
        endif ()

        # 推导 Qt 安装目录
        set(QT_INSTALL_PATH "${Qt5_DIR}/../../../")
        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
            if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
                set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
            endif ()
        endif ()

        # 平台插件 (Windows 必需)
        if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
            execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
                    "${dest_dir}/plugins/platforms/")
            execute_process(COMMAND ${CMAKE_COMMAND} -E copy
                    "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
                    "${dest_dir}/plugins/platforms/")
        endif ()

        # Qt 库和插件目录映射（相对完整）
        set(QT_PLUGIN_MAP
                Gui "platforms;imageformats;iconengines;platforminputcontexts;styles"
                Widgets "platforms;imageformats;iconengines;platforminputcontexts;styles"
                Network "bearer"
                Sql "sqldrivers"
                Svg "imageformats"
                Multimedia "mediaservice;audio"
                MultimediaWidgets "mediaservice;audio"
                Qml "qmltooling"
                Quick "scenegraph;qmltooling"
                Positioning "position"
                Sensors "sensors"
                Bluetooth "bluetooth"
                PrintSupport "printsupport"
                WebEngineCore "resources;translations"
                WebView "resources;translations"
                TextToSpeech "texttospeech"
                VirtualKeyboard "virtualkeyboard"
        )

        # 拷贝库和插件
        foreach (QT_LIB ${INSTALL_QT_LIBS_QT_LIBS})
            # DLL
            execute_process(COMMAND ${CMAKE_COMMAND} -E copy
                    "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll"
                    "${dest_dir}")

            # 查找插件映射
            list(FIND QT_PLUGIN_MAP ${QT_LIB} plugin_index)
            if (NOT plugin_index EQUAL -1)
                math(EXPR plugin_value_index "${plugin_index} + 1")
                list(GET QT_PLUGIN_MAP ${plugin_value_index} plugin_dirs_str)
                string(REPLACE ";" "|" plugin_dirs_pattern "${plugin_dirs_str}") # 防止 split 被误解
                string(REPLACE ";" ";" plugin_dirs "${plugin_dirs_str}")

                foreach (plugin_dir ${plugin_dirs})
                    set(src_plugin_dir "${QT_INSTALL_PATH}/plugins/${plugin_dir}")
                    set(dst_plugin_dir "${dest_dir}/plugins/${plugin_dir}")

                    if (EXISTS "${src_plugin_dir}")
                        execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${dst_plugin_dir}")
                        file(GLOB plugin_files "${src_plugin_dir}/*${DEBUG_SUFFIX}.dll")
                        foreach (plugin_file ${plugin_files})
                            execute_process(COMMAND ${CMAKE_COMMAND} -E copy
                                    "${plugin_file}" "${dst_plugin_dir}")
                        endforeach ()
                    endif ()
                endforeach ()
            endif ()
        endforeach ()
    endif ()
endfunction()


# \brief 函数名称 : create_log_config【创建日志配置】
# @log_name     : 日志名称
# @source_dir   : 源目录，in文件所在位置
# @dest_dir     : 输出目录
# 说明：此方法目前被logger提供的接口取代
function(create_log_config log_name source_dir dest_dir)
    if (NOT log_name)
        message(FATAL_ERROR "日志名称未指定")
    endif ()
    if (NOT source_dir)
        message(FATAL_ERROR "缺少源目录参数")
    endif ()
    if (NOT dest_dir)
        message(FATAL_ERROR "缺少输出目录参数")
    endif ()
    # 日志配置变量
    set(LOGGER_NAME ${log_name})

    if (NOT (EXISTS "${dest_dir}" AND NOT IS_DIRECTORY "${dest_dir}"))
        set(GENERATED_FILE "${dest_dir}/log_config.yaml")
    else ()
        set(GENERATED_FILE "${dest_dir}")
    endif ()

    # 生成最终的 YAML 文件
    #    if (NOT EXISTS ${GENERATED_FILE})
    #        message(STATUS "Logger config file not found, generating: ${GENERATED_FILE}")
    configure_file(
            ${source_dir}/log_config.yaml.in
            ${GENERATED_FILE}
            @ONLY
    )
    #    endif ()
endfunction()


#   +++++++++++++++++++ CMAKE MACROS +++++++++++++++++++++++#

# \brief 宏名称 : config_project【CXI公共配置逻辑】
# @is_qt_module : 是否为Qt依赖模块 True Or False
macro(config_project is_qt_module)
    if (MSVC)
        add_compile_options("/utf-8")
        add_compile_options("-DUNICODE -D_UNICODE")
    endif ()
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    if (${is_qt_module})
        set(CMAKE_AUTORCC ON)
        set(CMAKE_AUTOMOC ON)
        list(APPEND CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/uis")
        set(CMAKE_AUTOUIC ON)
        set(CMAKE_INCLUDE_CURRENT_DIR ON)
    endif ()
endmacro()

# \brief 宏名称    : add_standard_module【CXI添加标准模块宏】
# @target         : 库目标
# @export_location: 导出位置
# @is_shared      : 是否为动态库
# @is_qt_module   : 是否依赖Qt
macro(add_standard_module target export_location is_shared is_qt_module)
    if (${target} STREQUAL "")
        message(FATAL_ERROR "${target}目标不存在")
    endif ()
    if (NOT ${is_shared})
        message(FATAL_ERROR "动静态库配置参数不存在")
    endif ()
    if (NOT ${is_qt_module})
        message(FATAL_ERROR "Qt配置参数不存在")
    endif ()

    config_project(${is_qt_module})
    if (${is_qt_module})
        add_library(${target} SHARED)
    else ()
        add_library(${target})
    endif ()
    if (NOT ${export_location} STREQUAL "")
        export_symbol(${target} ${export_location})
    endif ()
    file(GLOB_RECURSE srcs CONFIGURE_DEPENDS
            "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
            "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp"
            "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
    file(GLOB_RECURSE srcs_p CONFIGURE_DEPENDS
            "${CMAKE_CURRENT_SOURCE_DIR}/private/*.cpp"
            "${CMAKE_CURRENT_SOURCE_DIR}/private/*.h")
    file(GLOB_RECURSE uis CONFIGURE_DEPENDS
            "${CMAKE_CURRENT_SOURCE_DIR}/uis/*.ui")
    file(GLOB_RECURSE qrcs CONFIGURE_DEPENDS
            "${CMAKE_CURRENT_SOURCE_DIR}/res/*.qrc")
    target_include_directories(${target} PUBLIC
            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
            $<INSTALL_INTERFACE:include>)
    target_include_directories(${target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/private")
    target_sources(${target} PRIVATE ${srcs} ${uis} ${srcs_p} ${qrcs})
endmacro()